package cn.buddha.jec.mvc.handler;

import cn.buddha.jec.exception.TongBusinessException;
import cn.buddha.jec.exception.TongBusinessResult;
import cn.buddha.jec.exception.enums.TongExceptionEnum;
import cn.buddha.jec.model.TongBaseResponse;
import cn.buddha.jec.model.TongContext;
import cn.buddha.jec.util.TongBeanUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * @ClassName AcGlobalExceptionHandler
 * @Author 友野浩二
 * @Description 全局的统一异常处理类
 * @Version 1.0
 *
 * <pre>
 * controller增强器：
 *      @ControllerAdvice(controller增强器) :
 *          被@ExceptionHandler、@InitBinder、@ModelAttribute注解的方法，都会作用在被 @RequestMapping注解的方法上。
 *      @ExceptionHandler(异常处理器) :
 *          此注解的作用是当出现其定义的异常时进行处理的方法。
 *
 *      RestControllerAdvice = @ControllerAdvice + @ResponseBody，该类中所有的方法都会返回json格式的数据。
 *      如果异常要返回也页面，则就使用@ControllerAdvice。
 * </pre>
 */
@RestControllerAdvice
@Slf4j
public class TongGlobalExceptionHandler {

    /**
     * ExceptionHandler拦截了异常，我们可以通过该注解实现自定义异常处理。其中，@ExceptionHandler 配置的 value 指定需要拦截的异常类型。
     * 发生异常时,只返回响应头(TongBaseResponse)信息
     */
    @ExceptionHandler(value = {Exception.class})
//    @ResponseBody
    public TongBaseResponse handlerException(Exception ex) {
        log.info("TongGlobalExceptionHandler.handlerException");
        log.info(ex.getMessage(), ex);
        TongContext tongContext = TongContext.getInstance();
        // 1- 处理 业务异常处理
        if (ex instanceof TongBusinessException) {
            TongBusinessException tongBusinessException = (TongBusinessException) ex;
            // 20190928 修改为BusinessResult.error()方法
//            return ExceptionResult.exception(businessException.getExceptionCode(), businessException.getExceptionMessage());
            TongBaseResponse tongBaseResponse = TongBusinessResult.error(tongBusinessException.getExceptionCode(), tongBusinessException.getExceptionMessage());
            tongBaseResponse.getTongOutHead().setFlowableId(tongContext == null ? null : tongContext.getFlowableId());
//            log.info("TongBaseRequest End, URI [{}]{}TongBaseResponse content is: {}",
//                    tongContext.getReqUrl(),
//                    System.lineSeparator(),
//                    tongBaseResponse);
            return tongBaseResponse;
        }

        // 2- 处理 除了 @RequestBody 注解方式的参数校验,比如controller中的方法入参注解为@RequestParam
        // TODO 建议还是写成切面，尽量把所有能控制的异常都由BusinessException来处理
//        if (ex instanceof BindException) {
//            BindException bindException = (BindException) ex;
//            BindingResult bindingResult = bindException.getBindingResult();
//            FieldError fieldError = bindingResult.getFieldError();
//
//            if (!TongBeanUtils.isNullObj(fieldError)) {
//                log.info("BindException, {}, {}", fieldError.getField(), fieldError.getDefaultMessage());
//
//                return TongBusinessResult.error(TongExceptionEnum.TRAN_ERROR.getCode(), getMessage(fieldError));
//            }
//        }

        // 3- 处理 @RequestBody注解方式的参数校验
        // TODO 建议还是写成切面(放在ValidateRequestAspect的前置通知)，尽量把所有能控制的异常都由BusinessException来处理
//        if (ex instanceof MethodArgumentNotValidException) {
//            MethodArgumentNotValidException methodArgumentNotValidException = (MethodArgumentNotValidException) ex;
//            BindingResult bindingResult = methodArgumentNotValidException.getBindingResult();
//            FieldError fieldError = bindingResult.getFieldError();
//
//            if (!TongBeanUtils.isNullObj(fieldError)) {
//                log.info("MethodArgumentNotValidException, {}, {}", fieldError.getField(), fieldError.getDefaultMessage());
//
//                return TongBusinessResult.error(TongExceptionEnum.TRAN_ERROR.getCode(), getMessage(fieldError));
//            }
//        }

        // 其他异常处理
        TongBaseResponse tongBaseResponse = TongBusinessResult.error(TongExceptionEnum.FAILED.getCode(), TongExceptionEnum.FAILED.getMessage());
        tongBaseResponse.getTongOutHead().setFlowableId(tongContext == null ? null : tongContext.getFlowableId());
//        log.info("TongBaseRequest End, URI [{}]{}TongBaseResponse content is: {}",
//                tongContext.getReqUrl(),
//                System.lineSeparator(),
//                tongBaseResponse);
        return tongBaseResponse;
    }

    private String getMessage(FieldError fieldError) {
        String message;
        try {
            // [字段名] + 错误消息
            message = "[".concat(fieldError.getField()).concat("]").concat(TongBeanUtils.nvl(fieldError.getDefaultMessage(), ""));
        } catch (Exception e) {
            message = fieldError.getDefaultMessage();
        }
        return message;
    }

}
